/*
 * Channel.cpp
 *
 *  Created on: Jul 14, 2016
 *      Author: Lucifer
 */

#include "./SelectableChannel.h"
#include "./SelectionKey.h"
#include "./Selector.h"

namespace BFX {

void SelectableChannel::close() {
	// TODO lock
	// Closes this channel
	if (_closed)
		return;
	_closed = true;

	closeImpl();
}

void SelectableChannel::closeImpl() {
	// cancels all of this channel's keys.
	boost::lock_guard<boost::recursive_mutex> sync(_keyLock);
	if (_keys) {
		for (size_t i = 0; i < _keyCapacity; i++) {
			if (_keys[i] != NULL)
				_keys[i]->cancel();
		}
		delete[] _keys;
		_keys = NULL;
		_keyCapacity = _keyCount = 0;
	}
}

SelectionKey* SelectableChannel::registerKey(Selector* sel, int ops, SelectCallback callback) {
	BFX_ASSERT((ops & ~getValidOps()) == 0);
	SelectionKey* key = findKey(sel);
	if (key == NULL) {
		// prevent multiple registration
		boost::lock_guard<boost::recursive_mutex> sync(_keyLock);
		// register a new key.
		key = sel->registerKey(this);
		addKey(key);
	}
	key->setInterestOps(ops, callback);
	return key;
}

SelectionKey* SelectableChannel::findKey(Selector* sel) {
	boost::lock_guard<boost::recursive_mutex> sync(_keyLock);
	if (_keys == NULL)
		return NULL;
	for (size_t i = 0; i < _keyCapacity; i++) {
		if (_keys[i] != NULL && _keys[i]->getSelector() == sel)
			return _keys[i];
	}
	return NULL;
}
void SelectableChannel::addKey(SelectionKey* key) {
	boost::lock_guard<boost::recursive_mutex> sync(_keyLock);
	size_t i = 0;
	if (_keys != NULL && _keyCount < _keyCapacity) {
		// find a free slot.
		for (i = 0; i < _keyCapacity; i++) {
			if (_keys[i] == NULL)
				break;
		}
	} else if (_keys == NULL) {
		// initialization
		_keys = new SelectionKey*[2];
	} else {
		// grow-up
		int n = _keyCapacity *= 2;
		SelectionKey** keys = new SelectionKey*[n];
		for (i = 0; i < _keyCapacity; i++) {
			keys[i] = _keys[i];
		}
		delete[] _keys;
		_keys = keys;
		_keyCapacity = n;
		i = _keyCount;
	}
	_keys[i] = key;
	_keyCount++;
}
void SelectableChannel::removeKey(SelectionKey* key) {
	boost::lock_guard<boost::recursive_mutex> sync(_keyLock);
	for (size_t i = 0; i < _keyCapacity; i++) {
		if (_keys[i] != NULL && _keys[i] == key) {
			_keys[i] = NULL;
			_keyCount--;
		}
	}
	key->invalidate();
}

} /* namespace BFX */
